<?php
/**
 * Created by PhpStorm.
 * User: mojie126
 * Date: 2017/4/27
 * Time: 下午11:31
 */

namespace app\index\controller;

use app\common\mailqueue;
use app\common\verify;
use OTPHP\TOTP;
use think\Controller;
use think\Session;
use think\Validate;

class LoginController extends Controller
{
	public function index()
	{
		if (!empty(Session::get("uid"))) {
			$this->error("已经登录", "/");
		}
		$this->assign("title", "登录");
		$url = input("r", "");
		$this->assign("url", $url);

		return $this->fetch();
	}

	public function doLogin()
	{
		$info = input("param.");

		//输入验证
		$rule = [
			"username|帐号" => "require",
			"password|密码" => "require|length:6,32",
			"__token__" => "require|token"
		];
		$msg = [
			"password" => "密码长度必须在 6~32 个字符之间",
			"__token__" => "请勿重复提交"
		];
		$data1 = [
			"username" => $info['username'],
			"password" => $info['password'],
			"__token__" => $info['__token__']
		];
		$validate = new Validate($rule, $msg);
		$check1 = $validate->check($data1);
		if (!$check1) {
			jsonReturn(2, $validate->getError());
		}
		//输入验证

		//登录验证
		//登录成功时发送邮件（可选）
		$check2 = db("users")->where("username|email", $info['username'])->field(["uid", "ban", "seal", "sealtime", "softdel", "safekey", "passsha", "confirm", "username", "2fa", "2fakey"])->find();
		if ($check2) {
			$passsha = md5(md5($check2['safekey'] . $info['password'] . $check2['username'] . $check2['safekey']));
			switch ($check2) {
				case $check2['confirm'] == 1:
					jsonReturn(0, "该账号未激活");
					break;
				case $check2['ban'] == 1:
					jsonReturn(0, "该账号已封禁");
					break;
				case $check2['seal'] == 1:
					jsonReturn(0, "该账号在 " . $check2['sealtime'] . " 挂起");
					break;
				case $check2['softdel'] == 1:
					jsonReturn(0, "该账号不存在");
					break;
				case $check2['passsha'] != $passsha:
					$where = [
						"uid" => ["=", $check2['uid']],
						"ip" => ["=", ip()],
					];
					$insert = [
						"num" => "1",
						"uid" => $check2['uid'],
						"ip" => ip()
					];
					$res = db("user_login_fail")->where($where)->find();
					if (empty($res)) {
						db("user_login_fail")->where($where)->insert($insert);
					} elseif ($res['num'] > 6) {//最大失败登录次数为6
						db("user_login_fail")->where($where)->update(["locktime" => nowtime()]);
						jsonReturn(0, "尝试登录次数超过最大限制", ["num" => $res['num'], "locktime" => $res['locktime'], "uid" => $res['uid']]);
					} else {
						db("user_login_fail")->where($where)->setInc("num");
					}
					jsonReturn(0, "密码错误");
					break;
				default:
					//2FA
					$pass2fa = 0;
					if ($check2['2fa'] == 1) {
						$totp = new TOTP($check2['username'], $check2['2fakey']);
						if ($info['otp'] == $totp->now()) {
							$pass2fa = 1;
						}
					}
					if ($pass2fa == 1 || $check2['2fa'] != 1) {
						db()->transaction(function () use ($check2) {
							db("users")->where("uid", $check2['uid'])->update(["lasttime" => nowtime()]);
							db("user_login_ip")->insert([
								"uid" => $check2['uid'],
								"ip" => ip(),
								"area" => getIPAttr(ip()),
								"addtime" => nowtime()
							]);
						});
						Session::set("uid", $check2['uid']);
						jsonReturn(1, "", ["uid" => $check2['uid']]);
					} else {
						jsonReturn(0, "两步验证失败");
					}
					break;
			}
		} else {
			jsonReturn(0, "该账号不存在");
		}
		//登录验证
	}

	public function doLogout()
	{
		Session::clear();
		if (empty(Session::get("uid"))) {
			$this->success("账号登出成功", "/index/login");
		}
	}

	public function resetPassword()
	{
		$this->assign("title", "重置密码");

		return $this->fetch();
	}

	public function doResetPassword()
	{
		$info = input("param.");

		//输入验证
		$rule = [
			"email|邮箱" => "require|email",
			"__token__" => "require|token"
		];
		$msg = [
			"email" => "邮箱格式错误",
			"__token__" => "请勿重复提交"
		];
		$data1 = [
			"email" => $info['email'],
			"__token__" => $info['__token__']
		];
		$validate = new Validate($rule, $msg);
		$check1 = $validate->check($data1);
		if (!$check1) {
			jsonReturn(2, $validate->getError());
		}
		//输入验证

		$check2 = db("users")->where("email", $info['email'])->field(["ban", "seal", "sealtime", "softdel", "email"])->find();
		if ($check2) {
			switch ($check2) {
				case $check2['ban'] == 1:
					jsonReturn(0, "该账号已封禁");
					break;
				case $check2['seal'] == 1:
					jsonReturn(0, "该账号在 " . $check2['sealtime'] . " 挂起");
					break;
				case $check2['softdel'] == 1:
					jsonReturn(0, "该账号不存在");
					break;
				default:
					if (empty($info['exp'])) {
						$info['exp'] = 3600;
					}
					$jwt = verify::encode($check2['email'], $info['exp']);
					//可以自己修改邮件内容，支持HTML ↓
					$msg = "请在1小时内点击链接并重新设置密码：<a href=" . getWebURL() . url("/index/login/confirmPassword", ["verify" => $jwt]) . " target='_blank'>点我点我</a>";
					//可以自己修改邮件内容，支持HTML ↑
					$res = mailqueue::mailqueue($check2['email'], "重置密码", $msg);
					if ($res) {
						jsonReturn(1, "邮件发送成功，请注意查收（包括垃圾箱）");
					} else {
						jsonReturn(0, "邮件发送失败，请稍后再试");
					}
					break;
			}
		} else {
			jsonReturn(0, "未找到使用该邮箱的注册用户");
		}
	}

	public function confirmPassword()
	{
		$info = input("param.");
		$this->assign("title", "修改密码");
		if (!empty($info['verify'])) {
			$res = verify::decode($info["verify"]);
			if (!$res) {
				$this->error("链接已失效", "/index/login");
			} else {
				$this->assign("email", $res->sub);
			}
		} else {
			$this->error("链接不存在", "/index/login");
		}

		return $this->fetch();
	}

	public function doConfirmPassword()
	{
		$info = input("param.");

		//输入验证
		$rule = [
			"password1|密码" => "require|length:6,32",
			"password2" => "require|confirm:password1",
			"__token__" => "require|token"
		];
		$msg = [
			"password1" => "密码长度必须在 6~32 个字符之间",
			"password2" => "两次密码不一致",
			"__token__" => "请勿重复提交"
		];
		$data1 = [
			"password1" => $info['password1'],
			"password2" => $info['password2'],
			"__token__" => $info['__token__']
		];
		$validate = new Validate($rule, $msg);
		$check1 = $validate->check($data1);
		if (!$check1) {
			jsonReturn(2, $validate->getError());
		}
		//输入验证

		$check2 = db("users")->where("email", $info['email'])->field(["uid", "ban", "seal", "sealtime", "softdel", "safekey", "username"])->find();
		if ($check2) {
			switch ($check2) {
				case $check2['ban'] == 1:
					jsonReturn(0, "该账号已封禁");
					break;
				case $check2['seal'] == 1:
					jsonReturn(0, "该账号在 " . $check2['sealtime'] . " 挂起");
					break;
				case $check2['softdel'] == 1:
					jsonReturn(0, "该账号不存在");
					break;
				default:
					$passsha = md5(md5($check2['safekey'] . $info['password1'] . $check2['username'] . $check2['safekey']));
					db("users")->where("uid", $check2['uid'])->update(["passsha" => $passsha]);
					jsonReturn(1, "密码修改成功");
					break;
			}
		} else {
			jsonReturn(0, "未找到使用该邮箱的注册帐号");
		}
	}

	public function confirmOK()
	{
		$this->assign("title", "重发验证");

		return $this->fetch();
	}

	public function doConfirmOK()
	{
		$info = input("param.");

		//输入验证
		$rule = [
			"email|邮箱" => "require|email",
			"__token__" => "require|token"
		];
		$msg = [
			"email" => "邮箱格式错误",
			"__token__" => "请勿重复提交"
		];
		$data1 = [
			"email" => $info['email'],
			"__token__" => $info['__token__']
		];
		$validate = new Validate($rule, $msg);
		$check1 = $validate->check($data1);
		if (!$check1) {
			jsonReturn(2, $validate->getError());
		}
		//输入验证

		$check2 = db("users")->where("email", $info['email'])->field(["email", "confirm"])->find();
		if ($check2) {
			//confirm == 1是需要邮件确认
			if ($check2['confirm'] == 1) {
				if (empty($info['exp'])) {
					$info['exp'] = 3600;
				}
				$jwt = verify::encode($check2['email'], $info['exp']);
				//可以自己修改邮件内容，支持HTML ↓
				$msg = "请在1小时内点击链接进行邮箱认证：<a href=" . getWebURL() . url("/index/login/doConfirmUser", ["verify" => $jwt]) . " target='_blank'>点我点我</a>";
				//可以自己修改邮件内容，支持HTML ↑
				$res = mailqueue::mailqueue($check2['email'], "邮箱认证", $msg);
				if ($res) {
					jsonReturn(1, "邮件发送成功，请注意查收（包括垃圾箱）");
				} else {
					jsonReturn(0, "邮件发送失败，请稍后再试");
				}
			} else {
				jsonReturn(0, "该帐号不需要邮邮箱证或已经邮箱认证完成");
			}
		} else {
			jsonReturn(0, "未找到使用该邮箱的注册帐号");
		}
	}

	public function doConfirmUser()
	{
		$info = input("param.");
		if (!empty($info['verify'])) {
			$res = verify::decode($info["verify"]);
			if (!$res) {
				$this->error("链接已失效", "/index/login");
			} else {
				db("users")->where("email", $res->sub)->update(["confirm" => 0]);
				$this->success("帐号完成认证", "/index/login");
			}
		} else {
			$this->error("链接不存在", "/index/login");
		}
	}

	public function confirm2FA()
	{
		$this->assign("title", "重置2FA");
		$info = input("param.");
		if (!empty($info['verify'])) {
			$res = verify::decode($info["verify"]);
			if (!$res) {
				$this->error("链接已失效", "/index/login");
			} else {
				$check = db("users")->where("username", $res->sub)->update(["2fa" => 0]);
				if ($check) {
					$this->success("已清除2FA，请登录", "/index/login");
				} else {
					$this->error("根本就没有绑定2FA (ー`´ー)", "/index/login");
				}
			}
		}

		return $this->fetch();
	}

	public function doConfirm2FA()
	{
		$info = input("param.");

		//输入验证
		$rule = [
			"username|帐号" => "require|length:2,18",
			"password|密码" => "require|length:6,32",
			"email|邮箱" => "require|email",
			"__token__" => "require|token"
		];
		$msg = [
			"username" => "帐号长度必须在 2~18 个字符之间",
			"password" => "密码长度必须在 6~32 个字符之间",
			"email" => "邮箱格式错误",
			"__token__" => "请勿重复提交"
		];
		$data1 = [
			"username" => $info['username'],
			"password" => $info['password'],
			"email" => $info['email'],
			"__token__" => $info['__token__']
		];
		$validate = new Validate($rule, $msg);
		$check1 = $validate->check($data1);
		if (!$check1) {
			jsonReturn(2, $validate->getError());
		}
		//输入验证

		$where = [
			"email" => ["=", $info['email']],
			"username" => ["=", $info['username']]
		];
		$check2 = db("users")->where($where)->field(["ban", "seal", "sealtime", "softdel", "email", "username", "safekey", "passsha"])->find();
		if ($check2) {
			$passsha = md5(md5($check2['safekey'] . $info['password'] . $check2['username'] . $check2['safekey']));
			switch ($check2) {
				case $check2['ban'] == 1:
					jsonReturn(0, "该账号已封禁");
					break;
				case $check2['seal'] == 1:
					jsonReturn(0, "该账号在 " . $check2['sealtime'] . " 挂起");
					break;
				case $check2['softdel'] == 1:
					jsonReturn(0, "该账号不存在");
					break;
				case $check2['passsha'] != $passsha:
					jsonReturn(0, "密码错误");
					break;
				default:
					if (empty($info['exp'])) {
						$info['exp'] = 1800;
					}
					$jwt = verify::encode($check2['username'], $info['exp']);
					//可以自己修改邮件内容，支持HTML ↓
					$msg = "请在30分钟内点击链接并重置2FA：<a href=" . getWebURL() . url("/index/login/confirm2FA", ["verify" => $jwt]) . " target='_blank'>点我点我</a>";
					//可以自己修改邮件内容，支持HTML ↑
					$res = mailqueue::mailqueue($check2['email'], "重置2FA", $msg);
					if ($res) {
						jsonReturn(1, "邮件发送成功，请注意查收（包括垃圾箱）");
					} else {
						jsonReturn(0, "邮件发送失败，请稍后再试");
					}
					break;
			}
		} else {
			jsonReturn(0, "该账号不存在，或所提供信息不一致");
		}
	}
}